// 
// DockablePanel.cs
//  
// Author:
//       Tomas Vondracek <tomas.vondracek@gmail.com>
// 
// Copyright (c) 2009 Tomas Vondracek
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;

using Common.Interfaces;

namespace Common.Gui.GuiWinFormsLib.Controls
{
	/// <summary>
	/// DockablePanel - should be placed in docking containerm  
	/// it can minimize itself with its content
	/// </summary>
	public class DockablePanel : UserControl, IDisposable, Common.Interfaces.IDockablePanel
	{
		/// <summary>
		/// current panel state 
		/// </summary>
		protected DockablePanelState currentState;
		public event Common.Interfaces.DockablePanelStateChanged HandleDockablePanelStateChanged;
		public event EventHandler DockablePanelAlignmentChanged;
		public event EventHandler DockablePanelTitleTextChanged;

		#region Controls definition

		protected CustomDrawnPanel controlPanel;

		protected Button btnMinimize;
		protected Button btnRestore;
		protected Label lblTitle;
		protected ToolTip toolTip1;
		private IContainer components;
		protected ContextMenuStrip contextMenuDoackablePanel;
		protected ToolStripMenuItem menuHide;
		protected ToolStripMenuItem menuRestore;
		protected ToolStripMenuItem menuAutohiding;
		#endregion

		protected int lastContentHeight;
		private PanelAlignment alignment;
		protected bool useDecorations;

		private Size preferredMinimumSize;
		protected Panel contentPanel;

		/// <summary>
		/// Minimum size used when panel is not minimized or hidden
		/// </summary>
		public Size PreferredMinimumSize
		{
			get { return preferredMinimumSize; }
		}

		private Brush brush;

		protected Brush Brush
		{
			get { return brush; }
			set { brush = value; }
		}

		/// <summary>
		/// color used for decoration
		/// </summary>
		//[DefaultValue(typeof(Color), System.Drawing.Color.FromArgb(193, 204, 219).ToString())]
		public Color DecorationColor
		{
			get;
			set;
		}

		public DockablePanel ()
		{
			InitializeComponent();		//designer method
			
			this.DeclareEvents ();

			// for begin, panel is normaly shown
			this.currentState = DockablePanelState.Normal;

			if (this.useDecorations)
				this.brush = new HatchBrush(HatchStyle.Percent20, this.DecorationColor, this.BackColor);
			else
				this.brush = new SolidBrush(this.BackColor);

			// this is something between green and blue
			// TODO theming should take care of it
			this.BackColor = System.Drawing.Color.FromArgb(156, 170, 193);
		}
		
		/// <summary>
		/// declare all events for this control
		/// </summary>
		protected void DeclareEvents ()
		{			
			this.controlPanel.MouseEnter += HandleControlPanelMouseEnter;
			this.controlPanel.MouseLeave += HandleControlPanelMouseLeave;
			
			this.btnMinimize.Click += HandleBtnMinimizeClick;
			this.btnRestore.Click += HandleBtnRestoreClick;
			
			this.HandleDockablePanelStateChanged += OnDockablePanelStateChanged;
			this.DockablePanelAlignmentChanged += HandleDockablePanelAlignmentChanged;

			this.ControlAdded += new ControlEventHandler(DockablePanel_ControlAdded);

			//this.Resize += new EventHandler(DockablePanel_Resize);

//			ZVI.Settings.LookAndFeelSettings settings = (ZVI.Settings.LookAndFeelSettings)Settings.Settings.GetInstance().GetSettings("LookAndFeel");
//			if (settings.enableTheming)
				//this.Paint += new PaintEventHandler(DockablePanel_Paint);
		}
		
		void DockablePanel_Paint(object sender, PaintEventArgs e)
		{
			Graphics g = e.Graphics;

			if (this.useDecorations)
				g.FillRectangle(brush, this.Bounds); 
			else
				g.Clear(this.BackColor);
		}

		void DockablePanel_Resize(object sender, EventArgs e)
		{
			// not used for now!
			var controlPanelHeight = this.controlPanel.Visible ? this.controlPanel.Height : 0;
			//this.SuspendLayout();
			//var newHeight = this.controlPanel.Visible ? this.Height - this.controlPanel.Height : this.Height;

			//if (this.contentPanel.Height != newHeight ||
			//    this.contentPanel.Width != this.Width)
			//{
			//    this.contentPanel.Location = new Point(0, this.controlPanel.Height);
			//    Size resized = new Size(this.Width, newHeight);
			//    this.contentPanel.Size = resized;
			//    //Console.WriteLine("{0}: resize from {1} to size {2}", this.TitleText, sender.ToString(), this.contentPanel.Size.ToString());
			//}            

			//this.ResumeLayout(true);

			this.contentPanel.Location = new Point(0, controlPanelHeight);
			this.contentPanel.Size = new Size(this.Width, this.Height - controlPanelHeight);
		}

		void DockablePanel_ControlAdded(object sender, ControlEventArgs e)
		{
			// TODO
			throw new NotImplementedException("Use AddContent Method.");
		}
		
		private void HandleDockablePanelAlignmentChanged (object sender, EventArgs e)
		{
			this.SuspendLayout();

			var controlPanelHeight = this.controlPanel.Visible ? this.controlPanel.Height : 0;

			switch (alignment)
			{
				case PanelAlignment.VerticalLeft:
					this.controlPanel.Dock = DockStyle.Right;
					this.contentPanel.Location = new Point(0, 0);
					break;
				case PanelAlignment.HorizontalBottom:
					this.contentPanel.Location = new Point(0, controlPanelHeight);
					this.controlPanel.Dock = DockStyle.Top;
					break;
				case PanelAlignment.HorizontalTop:
					this.contentPanel.Location = new Point(0, 0);
					this.controlPanel.Dock = DockStyle.Left;
					break;
				case PanelAlignment.VerticalRight:
					this.contentPanel.Location = new Point(0, 0);
					this.controlPanel.Dock = DockStyle.Bottom;
					break;
				case PanelAlignment.None:
				default:
					this.contentPanel.Location = new Point(0, controlPanelHeight);
					this.controlPanel.Dock = DockStyle.Top;
					Logging.Logger.AddInfo("Unknown " + alignment + " alignment in DockablePanel");
					break;
			}
			
			this.ResumeLayout(true);
		}

		/// <summary>
		/// used to update context menu after state changed
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		protected virtual void OnDockablePanelStateChanged (object sender)
		{
			switch (this.currentState) 
			{
			case DockablePanelState.Normal:
				this.ShowView();
				break;
			case DockablePanelState.Hidden:
				this.HideView();
				break;
//			case DockablePanelState.AutoHiding:	//TODO
				//break;
			case DockablePanelState.Maximalized:
				break;
			default:
				Logging.Logger.AddWarning("passing panel state " + this.currentState.ToString());
				break;
			}
		}

		protected void HandleBtnMinimizeClick (object sender, EventArgs e)
		{
			this.CurrentState = DockablePanelState.Hidden;	
		}
		
		protected void HandleBtnRestoreClick (object sender, EventArgs e)
		{
			this.CurrentState = DockablePanelState.Normal;
		}
		
		protected void HandleControlPanelMouseLeave (object sender, EventArgs e)
		{
			this.controlPanel.BackColor = SystemColors.Control;
		}

		protected void HandleControlPanelMouseEnter (object sender, EventArgs e)
		{
			this.controlPanel.BackColor = SystemColors.ControlLight;
		}
		
		/// <summary>
		/// gets or sets the height of control panel ( bar with minimize/restore butttons)
		/// </summary>
		public int ControlsBarHeight
		{
			get
			{
				return this.controlPanel.Height;
			}
			set
			{
				this.controlPanel.Height = value;
			}
		}

		/// <summary>
		/// true to make control bar visible,
		/// control bar contains buttons for panel operations and title text
		/// </summary>
		public bool ShowControlBar
		{
			get
			{
				return this.controlPanel.Visible;
			}
			set
			{
				this.controlPanel.Visible = value;
				DockablePanel_Resize(this, EventArgs.Empty);
			}
		}

		/// <summary>
		/// Current Panel State,
		/// if set new state, event is fired
		/// </summary>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public DockablePanelState CurrentState {
			get {
				return currentState;
			}
			set {
				currentState = value;
							
				//fire up the event about changing state
				if (this.HandleDockablePanelStateChanged != null)
				{
					this.HandleDockablePanelStateChanged(this);
				}
			}
		}
		
		/// <summary>
		/// text displayed in the panel header
		/// </summary>
		public string TitleText
		{
			get {
				return this.lblTitle.Text;
			}
			set {
				this.lblTitle.Text = value;
				
				if (this.DockablePanelTitleTextChanged !=null)
					this.DockablePanelTitleTextChanged(this, EventArgs.Empty);
			}
		}

		/// <summary>
		/// panel alignment, determine where to draw to control panel
		/// </summary>
		public PanelAlignment Alignment {
			get {
				return alignment;
			}
			set {
				alignment = value;
								
				//fire up the event about changing alignment
				if (this.DockablePanelAlignmentChanged != null)
				{
					this.DockablePanelAlignmentChanged(this, EventArgs.Empty);
				}
			}
		}
		
		/// <summary>
		/// adds control to the panel a fill the panel with it 
		/// </summary>
		/// <param name="content">
		/// A <see cref="Control"/> to add
		/// </param>
		public void AddContent(Control content)
		{
			if (content == null)
				return;

			// avoid having zero minimum size
			this.preferredMinimumSize = (content.MinimumSize.IsEmpty) ? new Size(100, 100) : content.MinimumSize;
			//when the panel is being minimized, we need to override the minimumsize
			this.MinimumSize = this.preferredMinimumSize;
			this.MaximumSize = content.MaximumSize;
			content.Dock = DockStyle.Fill;
			this.contentPanel.Controls.Add(content);
		}
		
		
		#region IView
		/// <summary>
		/// hides this panel, make it not visible
		/// </summary>
		public void HideView()
		{
			Logging.Logger.AddInfo("Hiding panel: " + this.ToString());
			this.MinimumSize = new Size(0, 0);
			this.Visible = false;
		}

		/// <summary>
		/// shows this panel, make it visible
		/// </summary>
		public void ShowView()
		{
			Logging.Logger.AddInfo("Showing panel: " + this.ToString());

			this.MinimumSize = this.preferredMinimumSize;
			this.Visible = true;

		}

		public bool IsVisible
		{
			get { return this.Visible; }
		}		

		#endregion
		
		#region IDisposable implementation
		void IDisposable.Dispose ()
		{
			this.contentPanel.Dispose();
			this.controlPanel.Dispose();
			
			base.Dispose();
		}
		
		#endregion

		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
			this.contextMenuDoackablePanel = new System.Windows.Forms.ContextMenuStrip(this.components);
			this.menuHide = new System.Windows.Forms.ToolStripMenuItem();
			this.menuRestore = new System.Windows.Forms.ToolStripMenuItem();
			this.menuAutohiding = new System.Windows.Forms.ToolStripMenuItem();
			this.contentPanel = new System.Windows.Forms.Panel();
			this.controlPanel = new Common.Gui.GuiWinFormsLib.Controls.CustomDrawnPanel();
			this.btnMinimize = new System.Windows.Forms.Button();
			this.btnRestore = new System.Windows.Forms.Button();
			this.lblTitle = new System.Windows.Forms.Label();
			this.contextMenuDoackablePanel.SuspendLayout();
			this.controlPanel.SuspendLayout();
			this.SuspendLayout();
			// 
			// toolTip1
			// 
			this.toolTip1.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info;
			this.toolTip1.ToolTipTitle = "Dockable Panel";
			// 
			// contextMenuDoackablePanel
			// 
			this.contextMenuDoackablePanel.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
			this.menuHide,
			this.menuRestore,
			this.menuAutohiding});
			this.contextMenuDoackablePanel.Name = "contextMenuDoackablePanel";
			this.contextMenuDoackablePanel.Size = new System.Drawing.Size(140, 70);
			this.contextMenuDoackablePanel.ItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.contextMenuDoackablePanel_ItemClicked);
			// 
			// menuHide
			// 
			this.menuHide.Image = global::Common.Gui.GuiWinFormsLib.Properties.Resources.arrow_down;
			this.menuHide.Name = "menuHide";
			this.menuHide.Size = new System.Drawing.Size(139, 22);
			this.menuHide.Text = "&Hide";
			// 
			// menuRestore
			// 
			this.menuRestore.Image = global::Common.Gui.GuiWinFormsLib.Properties.Resources.bullet_black;
			this.menuRestore.Name = "menuRestore";
			this.menuRestore.Size = new System.Drawing.Size(139, 22);
			this.menuRestore.Text = "&Restore";
			// 
			// menuAutohiding
			// 
			this.menuAutohiding.Enabled = false;
			this.menuAutohiding.Name = "menuAutohiding";
			this.menuAutohiding.Size = new System.Drawing.Size(139, 22);
			this.menuAutohiding.Text = "&Auto Hiding";
			// 
			// contentPanel
			// 
			this.contentPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
						| System.Windows.Forms.AnchorStyles.Left)
						| System.Windows.Forms.AnchorStyles.Right)));
			this.contentPanel.CausesValidation = false;
			this.contentPanel.Location = new System.Drawing.Point(0, 16);
			this.contentPanel.Margin = new System.Windows.Forms.Padding(0);
			this.contentPanel.Name = "contentPanel";
			this.contentPanel.Size = new System.Drawing.Size(506, 260);
			this.contentPanel.TabIndex = 2;
			// 
			// controlPanel
			// 
			this.controlPanel.Color1 = System.Drawing.SystemColors.ControlDark;
			this.controlPanel.Color2 = System.Drawing.SystemColors.ControlLight;
			this.controlPanel.Controls.Add(this.btnMinimize);
			this.controlPanel.Controls.Add(this.btnRestore);
			this.controlPanel.Controls.Add(this.lblTitle);
			this.controlPanel.Dock = System.Windows.Forms.DockStyle.Top;
			this.controlPanel.HighlightColor = System.Drawing.Color.GreenYellow;
			this.controlPanel.Location = new System.Drawing.Point(0, 0);
			this.controlPanel.Margin = new System.Windows.Forms.Padding(0);
			this.controlPanel.Name = "controlPanel";
			this.controlPanel.Size = new System.Drawing.Size(506, 16);
			this.controlPanel.TabIndex = 1;
			// 
			// btnMinimize
			// 
			this.btnMinimize.BackgroundImage = global::Common.Gui.GuiWinFormsLib.Properties.Resources.arrow_down_small;
			this.btnMinimize.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
			this.btnMinimize.Dock = System.Windows.Forms.DockStyle.Right;
			this.btnMinimize.ImageAlign = System.Drawing.ContentAlignment.BottomCenter;
			this.btnMinimize.Location = new System.Drawing.Point(474, 0);
			this.btnMinimize.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
			this.btnMinimize.Name = "btnMinimize";
			this.btnMinimize.Size = new System.Drawing.Size(16, 16);
			this.btnMinimize.TabIndex = 0;
			this.toolTip1.SetToolTip(this.btnMinimize, "Minimize Panel");
			this.btnMinimize.UseVisualStyleBackColor = true;
			// 
			// btnRestore
			// 
			this.btnRestore.BackgroundImage = global::Common.Gui.GuiWinFormsLib.Properties.Resources.bullet_black_small;
			this.btnRestore.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
			this.btnRestore.Dock = System.Windows.Forms.DockStyle.Right;
			this.btnRestore.Location = new System.Drawing.Point(490, 0);
			this.btnRestore.Margin = new System.Windows.Forms.Padding(3, 1, 3, 1);
			this.btnRestore.Name = "btnRestore";
			this.btnRestore.Size = new System.Drawing.Size(16, 16);
			this.btnRestore.TabIndex = 0;
			this.toolTip1.SetToolTip(this.btnRestore, "Restore origin size of Panel");
			this.btnRestore.UseVisualStyleBackColor = true;
			this.btnRestore.Visible = false;
			// 
			// lblTitle
			// 
			this.lblTitle.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
			this.lblTitle.AutoSize = true;
			this.lblTitle.BackColor = System.Drawing.Color.Transparent;
			this.lblTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
			this.lblTitle.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.lblTitle.Location = new System.Drawing.Point(300, 1);
			this.lblTitle.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0);
			this.lblTitle.Name = "lblTitle";
			this.lblTitle.Size = new System.Drawing.Size(27, 13);
			this.lblTitle.TabIndex = 0;
			this.lblTitle.Text = "Title";
			this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// DockablePanel
			// 
			this.ContextMenuStrip = this.contextMenuDoackablePanel;
			this.Controls.Add(this.contentPanel);
			this.Controls.Add(this.controlPanel);
			this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
			this.Margin = new System.Windows.Forms.Padding(0);
			this.Name = "DockablePanel";
			this.Size = new System.Drawing.Size(506, 276);
			this.contextMenuDoackablePanel.ResumeLayout(false);
			this.controlPanel.ResumeLayout(false);
			this.controlPanel.PerformLayout();
			this.ResumeLayout(false);

		}

		/// <summary>
		/// handle panel context menu
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected virtual void contextMenuDoackablePanel_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
		{
			if (e.ClickedItem.Equals(this.menuHide))
			{
				this.CurrentState = DockablePanelState.Hidden;
			}
			else if (e.ClickedItem.Equals(this.menuRestore))
			{
				this.CurrentState = DockablePanelState.Normal;
			}
		}
		
		/// <summary>
		/// instance string info
		/// </summary>
		/// <returns></returns>
		public override string ToString ()
		{
			return string.Format ("[DockablePanel: CurrentState={0}, TitleText={1}, Alignment={2}]", CurrentState, TitleText, Alignment);
		}
		
	}
}
